package indi.kider.server.bill.service;

import com.alibaba.fastjson.JSON;
import indi.kider.common.constant.*;
import indi.kider.common.model.apabus.Rent;
import indi.kider.common.model.apartment.Houses;
import indi.kider.common.model.bill.Bill;
import indi.kider.common.model.bill.BillPrepaidInfo;
import indi.kider.common.model.employee.Tenant;
import indi.kider.common.util.HttpClientUtils;
import indi.kider.server.apabus.mapper.RentMapper;
import indi.kider.server.apartment.mapper.HousesMapper;
import indi.kider.server.bill.exception.ProduceBillException;
import indi.kider.server.bill.mapper.BillMapper;
import indi.kider.server.bill.mapper.BillPrepaidInfoMapper;
import indi.kider.server.bill.model.CommRespRegitAndDeductModel;
import indi.kider.server.bill.model.MeterAnbsValue;
import indi.kider.server.employee.mapper.TenantMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 预付费相关的服务接口实现
 *
 * @author wangjingjing
 * @create 2018-09-20 上午10:07
 **/
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Service
@Slf4j
public class PrepaidBillServiceImpl implements PrepaidBillService {

    @Autowired
    private BillPrepaidInfoMapper billPrepaidInfoMapper;
    @Autowired
    private RentMapper            rentMapper;
    @Autowired
    private TenantMapper          tenantMapper;
    @Autowired
    private BillMapper            billMapper;
    @Autowired
    private HousesMapper          housesMapper;
    @Autowired
    private MeterCentreUtil       meterCentreUtil;


    @Override
    public void produceBillEveryDay() {
        /*
         * 1、对库中所有预付费类型的客户和表进行抽取
         * 2、抽取后对每户出具单日账单 注：billPrepaidInfo中的taskId 借用存放tenantId
         */
        List<Rent> rents = rentMapper.rentBillSoures(PayCons.PREPAID);
        // 获取前一天的时间
        LocalDate date = LocalDate.now();
        String ed = date.minusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        log.info("【补录{}的数据】", ed);
        rents.stream().forEach(rent -> {
            try {
                MeterAnbsValue meterAnbsValue = meterCentreUtil.
                        queryCrmFromServers(rent.getTenantId().toString(), ed);
                BILL_TYPE.forEach(type -> {
                    buildAndInsertRelatedBill(type, rent, meterAnbsValue);
                });
            } catch (ProduceBillException e) {
                log.info("【请求服务失败{}】", e.getStackTrace());
            }
        });
    }

    @Override
    public void settlementBillEveryDay() {
        /*
         * 1、对库中所有预付费账单进行抽取
         * 2、对账单进行钱包扣款
         * 3、扣款不成功的进行告警和相关的通知
         */
        List<BillPrepaidInfo> bills = billPrepaidInfoMapper.getNeedToDeductionBills();

        bills.stream().forEach(billPrepaidInfo -> {
            try {
                deductionBill(billPrepaidInfo);
            } catch (Exception e) {
                // 失败的进行处理
                billPrepaidInfo.setRemark("扣款异常");
                billPrepaidInfoMapper.updateByPrimaryKeySelective(billPrepaidInfo);
                log.info("【账单{}钱包扣款失败{}】", billPrepaidInfo, e.getStackTrace());
            }
        });

    }

    @Override
    public CommRespRegitAndDeductModel regitWallet(Long tenantId) {
        Rent rent = new Rent();
        rent.setTenantId(tenantId);
        rent.setState(RentStateCons.VALID);
        rent = rentMapper.selectOne(rent);

        if (rent == null) {
            return buildCommRespRegitAndDeductModel("请办理入住");
        }

        // 押金
        Float deposit = rent.getDeposit();
        if (deposit == null) {
            deposit = 0f;
        }
        Map<String, String> parmas = new HashMap<>();
        parmas.put("tenantId", String.valueOf(tenantId));
        Integer yajin = deposit.intValue() * 100;
        parmas.put("yaJin", yajin.toString());
        CommRespRegitAndDeductModel commRespRegitAndDeductModel = reqWallet(parmas, 1);
        if ("201".equals(commRespRegitAndDeductModel.getStatus())) {
            Tenant tenant = new Tenant();
            tenant.setId(tenantId);
            tenant.setWalletId(Long.valueOf(commRespRegitAndDeductModel.getData()));
            tenantMapper.updateByPrimaryKeySelective(tenant);
        }
        return commRespRegitAndDeductModel;
    }

    @Override
    public void summaryMonthBill(String month) {
        BillPrepaidInfo billPrepaidInfo = billPrepaidInfoMapper.selectByPrimaryKey(4121l);
        deductionBill(billPrepaidInfo);
    }

    @Override
    public List<CommRespRegitAndDeductModel> deductionBill(Long rendId) {
        List<CommRespRegitAndDeductModel> list     = new ArrayList<>();
        Rent                              rent     = rentMapper.selectByPrimaryKey(rendId);
        Long                              tenantId = rent.getTenantId();
        // 判断是否账单从钱包扣款 预付费且是线上支付。
        Houses houses = housesMapper.selectByPrimaryKey(rent.getHousesId());
        if (!(PayCons.PREPAID.equals(houses.getPostpaid()) && "2".equals(houses.getPayOnline()))) {
            list.add(buildCommRespRegitAndDeductModel("此用户不是线上支付的预付费用户"));
        } else {

            Example example = new Example(Bill.class);
            example.createCriteria().
                    andEqualTo("billAttribution", rendId).
                    andEqualTo("payState", 0);
            List<Bill> bills = billMapper.selectByExample(example);

            if (bills == null || bills.size() < 1) {
                list.add(buildCommRespRegitAndDeductModel("无需要扣款的账单"));
            } else {
                bills.forEach(bill -> {
                    CommRespRegitAndDeductModel commRespRegitAndDeductModel = new CommRespRegitAndDeductModel();
                    try {
                        // 去掉后面的两位小数
                        Integer money = (int) (bill.getTotal() * 100L);
                        commRespRegitAndDeductModel = deductionBill(String.valueOf(tenantId),
                                String.valueOf(bill.getBillType()),
                                String.valueOf(bill.getId()),
                                LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 00:00:00",
                                money.toString());
                        if ("201".equals(commRespRegitAndDeductModel.getStatus())) {
                            bill.setPayState(PayStateCons.PAYED);
                            bill.setPayType(PayTypeCons.WITHHOLDING);
                        }
                        bill.setRemark(commRespRegitAndDeductModel.getMsg());
                        billMapper.updateByPrimaryKeySelective(bill);
                    } catch (Exception e) {
                        log.info("扣款账单失败【{}】【{}】", bill, e.getStackTrace());
                        list.add(commRespRegitAndDeductModel);
                    }
                });
            }
        }

        return list;
    }

    @Override
    public void regitWallet() {
        Example example = new Example(Tenant.class);
        example.createCriteria().
                andEqualTo("walletId", 0).
                andEqualTo("state", 1);
        List<Tenant> tenants = tenantMapper.selectByExample(example);
        tenants.forEach(tenant -> {
            CommRespRegitAndDeductModel commRespRegitAndDeductModel = regitWallet(tenant.getId());
            log.info("【给用户{}注册钱包，注册结果{}】", tenant, commRespRegitAndDeductModel);
        });
    }

    @Override
    public List<BillPrepaidInfo> selectPrepaidInfoByRentId(Long rentId, String dateMoney) {
        /*
            1、 根据tenantId 找到rentId
            2、 获取BillPrepaidInfo的 归属rent的账单
         */
        Example example = new Example(BillPrepaidInfo.class);
        example.createCriteria().
                andEqualTo("billAttribution", rentId).
                andLike("billDate", dateMoney + "%");
        return billPrepaidInfoMapper.selectByExample(example);
    }

    @Override
    public void statisticalPrepaidDetailedBill() {

    }

    @Override
    public boolean judgingTheBalanceByTenantId(Long tenantId) {
        Example example = new Example(BillPrepaidInfo.class);
        example.createCriteria().
                andEqualTo("remark", "余额不足").
                andEqualTo("taskId", tenantId);
        int count = billPrepaidInfoMapper.selectCountByExample(example);
        log.info("【有{}个余额不足的记录】", count);
        return count < 1;
    }

    @Override
    public boolean canRefund(Long tenantId) {
        Rent record = new Rent();
        record.setState(RentStateCons.VALID);
        record.setTenantId(tenantId);
        /* 查询是否有在租住的。*/
        int recount = rentMapper.selectCount(record);
        /*再判断是否有欠费账单*/
        if (recount < 1) {
            log.info("【租户{}已经退租】", tenantId);
            Float arrears = billPrepaidInfoMapper.queryArrearsTotal(tenantId);
            log.info("【租户{}已经退租, 还欠款{}】", tenantId, arrears);
            return null == arrears;
        }
        return false;
    }

    // 需要的账单类型。
    private static final List<Integer> BILL_TYPE = Arrays.asList(BillTypeCons.WATER,
            BillTypeCons.POWER,
            BillTypeCons.W_SHARE,
            BillTypeCons.P_SHARE);

    CommRespRegitAndDeductModel buildCommRespRegitAndDeductModel(String msg) {
        CommRespRegitAndDeductModel commRespRegitAndDeductModel = new CommRespRegitAndDeductModel();
        commRespRegitAndDeductModel.setStatus("201");
        commRespRegitAndDeductModel.setMsg(msg);
        return commRespRegitAndDeductModel;
    }

    /**
     * 钱包账户扣款。
     *
     * @param billPrepaidInfo
     */
    BillPrepaidInfo deductionBill(BillPrepaidInfo billPrepaidInfo) {
        Long tenantId = billPrepaidInfo.getTaskId();
        // 去掉后面的两位小数
        Integer money = (int) (billPrepaidInfo.getTotal() * 100L);

        String    billDate = billPrepaidInfo.getBillDate();
        LocalDate dateTime = LocalDate.parse(billDate, DateTimeFormatter.ofPattern("yyyyMMdd"));
        billDate = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 00:00:00";

        CommRespRegitAndDeductModel commRespRegitAndDeductModel = deductionBill(String.valueOf(tenantId),
                String.valueOf(billPrepaidInfo.getBillType()),
                String.valueOf(billPrepaidInfo.getId()),
                billDate,
                money.toString()
        );
        if ("201".equals(commRespRegitAndDeductModel.getStatus())) {
            billPrepaidInfo.setPayState(PayStateCons.PAYED);
            billPrepaidInfo.setPayType(PayTypeCons.WITHHOLDING);
        }
        billPrepaidInfo.setRemark(commRespRegitAndDeductModel.getMsg());
        billPrepaidInfoMapper.updateByPrimaryKey(billPrepaidInfo);
        return billPrepaidInfo;
    }

    CommRespRegitAndDeductModel deductionBill(String tenantId, String billType,
                                              String billId, String billDate,
                                              String kkMoney) {
        Map<String, String> params = new HashMap();
        params.put("tenantId", tenantId);
        params.put("billType", billType);
        params.put("billId", billId);
        params.put("billDate", billDate);
        params.put("kkMoney", kkMoney);

        return reqWallet(params, 2);
    }


    CommRespRegitAndDeductModel reqWallet(Map pramas, Integer type) {
        String url = "";
        String str = "";
        switch (type) {
            case 1:
                //url = "https://pay.woniugm.com/member/wallet/createWallet";
                break;
            case 2:
                //url = "https://pay.woniugm.com/member/wallet/kkWallet";
                break;
        }
        log.info("请求【url= {},参数{}】", url, pramas);
        try {
            str = HttpClientUtils.postForm(url, pramas, null, 10000, 10000);
            log.info("请求的结果【{}】", str);
        } catch (Exception e) {
            log.info("请求的结果【{}】【{}】", str, e.getStackTrace());
        }


        return JSON.parseObject(str, CommRespRegitAndDeductModel.class);
    }

    /**
     * 组建明细账单并且入库。
     *
     * @param billType
     * @param rent
     * @param meterAnbsValue
     * @return
     */
    BillPrepaidInfo buildAndInsertRelatedBill(Integer billType, Rent rent, MeterAnbsValue meterAnbsValue) {
        String billDate = LocalDate.now().minusDays(1).format(DateTimeFormatter.ofPattern("yyyyMMdd"));

        BillPrepaidInfo billPrepaidInfo = new BillPrepaidInfo();
        billPrepaidInfo.setBillTime(new Date());
        billPrepaidInfo.setBillType(billType);
        billPrepaidInfo.setState(BillClientStateCons.VALID);
        billPrepaidInfo.setPayState(PayStateCons.UNPAYED);
        billPrepaidInfo.setRefund(1);
        billPrepaidInfo.setTaskId(rent.getTenantId());
        billPrepaidInfo.setBillDate(billDate);
        billPrepaidInfo.setBillAttribution(rent.getId());

        Float nmb   = getNmbByBillType(meterAnbsValue, billType);
        Float price = getPriceByBillType(rent, billType);
        Float total = price * nmb;

        billPrepaidInfo.setAbsoluteNumber(nmb);
        billPrepaidInfo.setPrice(price);
        billPrepaidInfo.setTotal(total);
        // total 为0 的照样生成账单明细。
        billPrepaidInfoMapper.insertOrUpdateSelective(billPrepaidInfo);
        return billPrepaidInfo;
    }

    /**
     * 获取用量
     *
     * @param meterAnbsValue
     * @param billType
     * @return
     */
    Float getNmbByBillType(MeterAnbsValue meterAnbsValue, Integer billType) {
        Float anbs = 0f;
        if (BillTypeCons.WATER.equals(billType)) {
            anbs = Float.valueOf(meterAnbsValue.getWaterConsumeValue());
        } else if (BillTypeCons.POWER.equals(billType)) {
            anbs = Float.valueOf(meterAnbsValue.getEleConsumeValue());
        } else if (BillTypeCons.P_SHARE.equals(billType)) {
            anbs = Float.valueOf(meterAnbsValue.getElePublicValue());
        } else if (BillTypeCons.W_SHARE.equals(billType)) {
            anbs = Float.valueOf(meterAnbsValue.getWaterPublicValue());
        }

        return anbs;
    }

    /**
     * 获取价格
     *
     * @param rent
     * @param billType
     * @return
     */
    Float getPriceByBillType(Rent rent, Integer billType) {
        Float anbs = 0f;
        if (BillTypeCons.WATER.equals(billType) || BillTypeCons.W_SHARE.equals(billType)) {
            anbs = rent.getWaterCost();
        } else if (BillTypeCons.POWER.equals(billType) || BillTypeCons.P_SHARE.equals(billType)) {
            anbs = rent.getPowerCost();
        }
        return anbs;
    }

}
